#include "SceneTree.h"
#include "TreeFunctors.h"

/* CSceneNodeControl */
CSceneNodeControl::CSceneNodeControl(CSceneNode *a_Node)
{
    m_Node = a_Node;
}

mVoid CSceneNodeControl::SetNode( CSceneNode * a_Node )
{
    m_Node = a_Node;
}

mBool CSceneNodeControl::SetPos( maths::CVector4f &a_Pos )
{
    if (m_Node == NULL)
        return false;

	maths::CMatrix4x4f Mtx = m_Node->GetL2P();
    Mtx[12] = a_Pos[0];
    Mtx[13] = a_Pos[1];
    Mtx[14] = a_Pos[2];
	m_Node->SetL2P(Mtx);
    return true;
}

mBool CSceneNodeControl::Scale( mFloat a_fXScale, mFloat a_fYScale, mFloat a_fZScale )
{
    if (m_Node == NULL)
        return false;

    maths::CMatrix4x4f Mtx = m_Node->GetL2P();
    Mtx[0]  *= a_fXScale;
    Mtx[4]  *= a_fXScale;
    Mtx[8]  *= a_fXScale;

    Mtx[1]  *= a_fYScale;
    Mtx[5]  *= a_fYScale;
    Mtx[9]  *= a_fYScale;

    Mtx[2]  *= a_fZScale;
    Mtx[6]  *= a_fZScale;
    Mtx[10] *= a_fZScale;
	m_Node->SetL2P(Mtx);
    return true;
}

mBool CSceneNodeControl::Scale( maths::CVector4f &a_Scale )
{
    return Scale(a_Scale[0], a_Scale[1], a_Scale[2]);
}

mBool CSceneNodeControl::Move(maths::CVector4f &a_Delta)
{
    if (m_Node == NULL)
        return false;

    maths::CMatrix4x4f Mtx = m_Node->GetL2P();
    Mtx[12] += a_Delta[0];
    Mtx[13] += a_Delta[1];
    Mtx[14] += a_Delta[2];
	m_Node->SetL2P(Mtx);
    return true;
}

/*mBool CSceneNodeControl::Rotate(maths::CVector4f &a_Dir, mFloat a_Angle)
{
    if (m_Node == NULL)
        return false;

    maths::CMatrix4x4f RotateMtx;
	RotateMtx.MakeRotateTransformDeg( a_Dir, a_Angle );
    m_Node->SetL2P( RotateMtx * m_Node->GetL2P() );
    return true;
}*/

mBool CSceneNodeControl::Rotate(maths::CVector4f &a_Vector)
{
	if (m_Node == NULL)
		return false;

	maths::CMatrix4x4f RotateMtx;
	RotateMtx.MakeRotateTransformDeg( maths::CVector4f(a_Vector[0], a_Vector[1], a_Vector[2], 0.0f), a_Vector[3] );
	m_Node->SetL2P( RotateMtx * m_Node->GetL2P() );
	return true;
}

mBool CSceneNodeControl::RotateInP2W(maths::CVector4f &a_Dir, mFloat a_Angle)
{
    if (m_Node == NULL)
        return false;

    maths::CMatrix4x4f RotateMtx;
	RotateMtx.MakeRotateTransformDeg( a_Dir, a_Angle );
    m_Node->SetL2P( m_Node->GetL2P() * RotateMtx );
    return true;
}

/* CSceneTree class */
CSceneNode* CSceneTree::m_World = NULL;

CSceneTree::CSceneTree()
{
 //   m_pDebug = NULL;
    /* if m_World already exists, new tree wouldn't be created!*/
    if (m_World == NULL)
        m_World = new CSceneNode;
}

//mVoid CSceneTree::SetDebugUnit( Debug *a_pDebug )
//{
//    m_pDebug = a_pDebug;
//}

mBool CSceneTree::AddChild( CSceneNode *a_Parent, CSceneNode *a_Child )
{
    if (a_Child == NULL)
        return false;

    if (a_Parent == NULL)
    {
        m_World->AddChild(a_Child);
    }
    else
    {
        a_Parent->AddChild(a_Child);
    }
    
    return true;
}

CSceneTree::~CSceneTree()
{
    (*g_pDebug) << "Erasing Scene Tree...\n";
	TreeFunctor::Delete Eraser;
    Iterate(Eraser);
    m_World = NULL;
}

mUInt CSceneTree::Iterate ( CSceneNodeRootFunctor &a_pRootFunctor, CSceneNode *a_pRoot )
{
	if (a_pRoot == NULL)
		return IRESULT_CONTINUE;

	switch (a_pRootFunctor(a_pRoot))
	{
	case IRESULT_STOP:
		return IRESULT_STOP;
	case IRESULT_SKIPCHILD:
		return IRESULT_CONTINUE;
	case IRESULT_CONTINUE:
		for each (CSceneNode *Child in a_pRoot->m_Childs)
			if (Iterate(a_pRootFunctor, Child) == IRESULT_STOP)
				return IRESULT_STOP;
	}
	return IRESULT_CONTINUE;
}

mUInt CSceneTree::Iterate ( CSceneNodeLeafFunctor &a_pLeafFunctor, CSceneNode *a_pRoot )
{
	if (a_pRoot == NULL)
		return IRESULT_CONTINUE;

	for each (CSceneNode *Child in a_pRoot->m_Childs)
		if (Iterate(a_pLeafFunctor, Child) == IRESULT_STOP)
			return IRESULT_STOP;
	if (a_pLeafFunctor(a_pRoot) == IRESULT_STOP)
		return IRESULT_STOP;
	return IRESULT_CONTINUE;
}

maths::CAABox &CSceneTree::BoundBox()
{
	TreeFunctor::TreeBoundBox BoxFunctor;
	return BoxFunctor.GetBox();
}